<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>音乐播放器和歌词编辑器</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f4f4f9;
        }
        .container {
            width: 60%;
            max-width: 600px;
            padding: 20px;
            background-color: white;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            border-radius: 8px;
            transition: background-color 0.3s;
        }
        .container.dragging {
            background-color: #e0e0e0;
        }
        audio {
            width: 100%;
            margin-bottom: 10px;
        }
        input[type="file"] {
            margin-bottom: 10px;
        }
        button {
            margin-right: 5px;
        }
        textarea {
            width: 100%;
            height: 200px;
            margin-top: 10px;
        }
        progress {
            width: 100%;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <input type="file" id="musicFileInput" accept=".mp3,.lrc" multiple>
        <div id="selectedFileName" style="margin-bottom: 10px;"></div>
        <audio id="audioPlayer" controls></audio>
        <button id="playPauseButton">播放 (F6)</button>
        <button id="rewindButton">后退5秒 (F7)</button>
        <button id="forwardButton">前进5秒 (F8)</button>
        <button id="timestampButton">踩点 (F9)</button>
        <button id="saveLyricsButton">保存歌词为LRC文件</button>
        <progress id="progressBar" value="0" max="1"></progress>
        <textarea id="lyricsTextarea" placeholder="在这里输入歌词..."></textarea>
    </div>

    <script>
        const container = document.querySelector('.container');
        const musicFileInput = document.getElementById('musicFileInput');
        const audioPlayer = document.getElementById('audioPlayer');
        const playPauseButton = document.getElementById('playPauseButton');
        const rewindButton = document.getElementById('rewindButton');
        const forwardButton = document.getElementById('forwardButton');
        const timestampButton = document.getElementById('timestampButton');
        const saveLyricsButton = document.getElementById('saveLyricsButton');
        const progressBar = document.getElementById('progressBar');
        const lyricsTextarea = document.getElementById('lyricsTextarea');
        const selectedFileNameElement = document.getElementById('selectedFileName');

        let currentAudioBlobUrl;
        let currentAudioFileName;

        // 阻止浏览器的默认行为，允许文件拖放
        ['dragenter', 'dragover', 'drop'].forEach(eventName => {
            container.addEventListener(eventName, preventDefaults, false);
        });

        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }

        // 添加和移除拖放指示样式
        container.addEventListener('dragenter', () => {
            container.classList.add('dragging');
        });

        container.addEventListener('dragleave', () => {
            container.classList.remove('dragging');
        });

        // 监听文件拖放完成事件
        container.addEventListener('drop', handleDrop, false);

        function handleDrop(e) {
            const files = e.dataTransfer.files;
            processFiles(files);
            container.classList.remove('dragging'); // 移除拖放指示样式
        }

        musicFileInput.addEventListener('change', (event) => {
            const files = event.target.files;
            processFiles(files);
        });

        function processFiles(files) {
            let audioFile = null;
            let lyricFile = null;

            for (const file of files) {
                if (file.type === 'audio/mpeg') {
                    audioFile = file;
                } else if (file.name.endsWith('.lrc')) {
                    lyricFile = file;
                }
            }

            if (audioFile) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    currentAudioBlobUrl = e.target.result;
                    audioPlayer.src = currentAudioBlobUrl;
                    audioPlayer.load();

                    // 获取文件名（去掉扩展名）
                    const fileName = audioFile.name.replace(/\.[^/.]+$/, '');
                    currentAudioFileName = fileName;
                    // 自动在歌词区域添加 [00:00:00] 歌名
                    lyricsTextarea.value = `[00:00.00]《${fileName}》\n`;

                    // 更新显示的文件名
                    selectedFileNameElement.textContent = `已选择文件: ${audioFile.name}`;

                    // 尝试加载同名歌词文件
                    if (lyricFile) {
                        loadLyricFile(lyricFile);
                    }
                };
                reader.readAsDataURL(audioFile); // 或者使用 readAsArrayBuffer(file)
            } else if (lyricFile) {
                loadLyricFile(lyricFile);
                // 更新显示的文件名为空，因为没有音频文件
                selectedFileNameElement.textContent = '';
            } else {
                // 如果没有选择任何文件，清除显示的文件名
                selectedFileNameElement.textContent = '';
            }
        }

        function loadLyricFile(file) {
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    // 明确指定使用 UTF-8 编码
                    const lyricsContent = new TextDecoder('UTF-8').decode(new Uint8Array(e.target.result));
                    lyricsTextarea.value = lyricsContent;
                } catch (error) {
                    console.error("读取歌词文件时出错:", error);
                    lyricsTextarea.value = "无法读取歌词文件，请检查文件编码。";
                }
            };
            reader.onerror = (e) => {
                console.error("读取文件时出错:", e);
                lyricsTextarea.value = "无法读取文件，请重试。";
            };
            reader.readAsArrayBuffer(file); // 使用 readAsArrayBuffer 以便进行编码转换
        }

        audioPlayer.addEventListener('loadedmetadata', () => {
            updatePlayPauseText();
        });

        audioPlayer.addEventListener('timeupdate', () => {
            if (!isNaN(audioPlayer.duration)) {
                progressBar.value = audioPlayer.currentTime / audioPlayer.duration;
            }
        });

        progressBar.addEventListener('click', (event) => {
            const rect = progressBar.getBoundingClientRect();
            const clickPosition = (event.clientX - rect.left) / rect.width;
            audioPlayer.currentTime = clickPosition * audioPlayer.duration;
        });

        playPauseButton.addEventListener('click', togglePlayPause);

        rewindButton.addEventListener('click', () => {
            audioPlayer.currentTime -= 5;
        });

        forwardButton.addEventListener('click', () => {
            audioPlayer.currentTime += 5;
        });

        timestampButton.addEventListener('click', insertTimestampAtCursor);

        saveLyricsButton.addEventListener('click', () => {
            const lrcContent = lyricsTextarea.value;
            const blob = new Blob([lrcContent], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            // 使用 currentAudioFileName 作为文件名，如果未定义，则默认为“未命名”
            a.download = currentAudioFileName || '未命名';
            a.download += '.lrc'; // 设置文件后缀为 .lrc
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        });

        document.addEventListener('keydown', (event) => {
            switch (event.key) {
                case 'F6':
                    event.preventDefault();
                    togglePlayPause();
                    break;
                case 'F7':
                    event.preventDefault();
                    audioPlayer.currentTime -= 5;
                    break;
                case 'F8':
                    event.preventDefault();
                    audioPlayer.currentTime += 5;
                    break;
                case 'F9':
                    event.preventDefault();
                    insertTimestampAtCursor();
                    break;
            }
        });

        function formatTime(seconds) {
            const minutes = Math.floor(seconds / 60).toString().padStart(2, '0');
            const remainingSeconds = Math.floor(seconds % 60).toString().padStart(2, '0');
            const milliseconds = Math.floor((seconds - Math.floor(seconds)) * 1000).toString().padStart(3, '0').slice(0, 2);
            return `${minutes}:${remainingSeconds}.${milliseconds}`;
        }

        function updatePlayPauseText() {
            playPauseButton.textContent = audioPlayer.paused ? '播放 (F6)' : '暂停 (F6)';
        }

        function togglePlayPause() {
            if (audioPlayer.paused) {
                audioPlayer.play();
            } else {
                audioPlayer.pause();
            }
            updatePlayPauseText();
        }

        function insertTimestampAtCursor() {
            const timestamp = formatTime(audioPlayer.currentTime);
            const start = lyricsTextarea.selectionStart;
            const end = lyricsTextarea.selectionEnd;
            const textBefore = lyricsTextarea.value.substring(0, start);

            // 找到当前行的起始位置和结束位置
            const currentLineStart = lyricsTextarea.value.lastIndexOf('\n', start - 1) + 1;
            const nextLineStart = lyricsTextarea.value.indexOf('\n', start);
            const currentLineEnd = nextLineStart === -1 ? lyricsTextarea.value.length : nextLineStart;

            // 提取当前行的内容
            const currentLine = lyricsTextarea.value.substring(currentLineStart, currentLineEnd).trim();

            // 计算 textAfter 为当前行的下一行到最后的内容
            const textAfter = nextLineStart !== -1 ? lyricsTextarea.value.substring(nextLineStart) : '';

            // 在当前行的开头插入时间标签
            const updatedText = textBefore.slice(0, currentLineStart) + `[${timestamp}]${currentLine}` + textAfter;
            lyricsTextarea.value = updatedText;

            // 设置光标到下一行的最前方
            const newCursorPos = Math.min(currentLineStart + timestamp.length + 3 + currentLine.length + 1, updatedText.length);
            lyricsTextarea.setSelectionRange(newCursorPos, newCursorPos);
            lyricsTextarea.focus();

            // 检查光标是否在可见范围内，如果不在上80%，则自动向下滚动一行
            checkAndScrollCursor();
        }

        // 处理点击事件，确保光标位置不变
        lyricsTextarea.addEventListener('click', (event) => {
            event.stopPropagation();
            lyricsTextarea.focus();
        });

        function getLineHeight(element) {
            const tempDiv = document.createElement('div');
            tempDiv.style.position = 'absolute';
            tempDiv.style.visibility = 'hidden';
            tempDiv.style.whiteSpace = 'pre';
            tempDiv.style.lineHeight = window.getComputedStyle(element).lineHeight;
            tempDiv.innerText = 'A\nB';
            document.body.appendChild(tempDiv);
            const lineHeight = tempDiv.offsetHeight / 2;
            document.body.removeChild(tempDiv);
            return lineHeight;
        }

        function checkAndScrollCursor() {
            const cursorPosition = lyricsTextarea.selectionStart;
            const textBeforeCursor = lyricsTextarea.value.substring(0, cursorPosition);
            const linesBeforeCursor = textBeforeCursor.split('\n').length - 1;
            const lineHeight = getLineHeight(lyricsTextarea);
            const visibleLines = lyricsTextarea.clientHeight / lineHeight;
            const scrollTop = lyricsTextarea.scrollTop;
            const cursorTop = linesBeforeCursor * lineHeight;

            if (cursorTop < scrollTop || cursorTop > scrollTop + visibleLines * lineHeight * 0.8) {
                lyricsTextarea.scrollTop = cursorTop - visibleLines * lineHeight * 0.4;
            }
        }
    </script>
</body>
</html>